using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;

namespace SharedObjects
{
	[DataContract]
	[ReferencedBy(typeof(SystemDirectory))]
	public class SystemFile : EntityBase
	{
		[DataMember] public ulong ParentId { get; set; }
		[DataMember] public ulong? CopyOf { get; set; } //if not null, determines it's originating fileid. this MAY point to non-existing files.
		[DataMember] public string Name { get; set; }
		[DataMember] public int Size { get; set; }
		
		[DataMember] public int DisplaySize { get; set; } //determined by Size and CompressionLevel
		[DataMember] public DateTime Time { get; set; }
		[DataMember] public FileType Type { get; set; }
		
		[DataMember] public int EncryptionLevel { get; set; }
		[DataMember] public int CompressionLevel { get; set; }
	
		[DataMember] public string Content { get; set; }
		[DataMember] public bool IsLocked { get; set; } //hidden flag to know if file is in use by anyone's mission etc
		[DataMember] public bool IsCopyProtected { get; set; } //prevents copying of a file. mainly used to prevent users from sharing credential or uploading them to low security file locations

		[DataMember] public int DeleteLevel { get; set; } //indicates which version of a deleter was used. Required for undelete operations
	
		public virtual SystemFile Copy(IObjectContainer db)
		{
			if (IsCopyProtected)
				return null;
			SystemFile source = this;
			//if source is a copy(!) of a credential file, copy protection must be turned on for the resulting copy, to allow for only 1 copy from that file.
			bool targetIsCopyProtected = false;
			if (source.CopyOf != 0)
			{
				var original = (from CredentialFile f in db where f.Id == source.CopyOf select f).FirstOrDefault();
				if (original != null) //if the CopyOf points to a CredentialFile
					targetIsCopyProtected = true;
			}
			SystemFile newFile = new SystemFile
			{
				Id = Extension.ToLong(Guid.NewGuid()),
				Name = source.Name,
				CompressionLevel = source.CompressionLevel,
				EncryptionLevel = source.EncryptionLevel,
				Content = source.Content,
				Size = source.Size,
				DisplaySize = source.DisplaySize,
				Time = source.Time,
				Type = source.Type,
				IsDeleted = source.IsDeleted,
				CopyOf = source.CopyOf ?? source.Id, //if the file already has a CopyOf set, then we take this over instead of creating a chain of copies
				DeletionTimeStamp = source.DeletionTimeStamp,
				IsCopyProtected = targetIsCopyProtected
			};
			return newFile;
		}
	}

	[DataContract]
	[ReferencedBy(typeof(ComputerSystem))]
	[ReferencedBy(typeof(SystemDirectory))]
	public class CredentialFile : SystemFile
	{
		/// <summary>
		/// This Copy() is being used by the creation process for credentials, ie. the copied CredFile does not reside in a directory, but it's copy does.
		/// </summary>
		/// <returns></returns>
		public override SystemFile Copy(IObjectContainer db)
		{
			return new SystemFile
			{
				CopyOf = Id, 
				Id = Extension.ToLong(Guid.NewGuid()), 
				Name = Name, 
				Size = Size,
				DisplaySize = DisplaySize, 
				Time = Time, 
				Type = Type, 
				IsLocked = false
			};
		}
	}

	public enum FileType
	{
		//todo: get values from old code
		Program,
		RainbowtableFile,
		Fingerprint,
		Retina,
		Dna,
		Psec,
		Tbpa
	}

	public class CredentialFileComparer : IEqualityComparer<CredentialFile>
	{
		public bool Equals(CredentialFile x, CredentialFile y)
		{
			if (x == y)
				return true;
			if (
				x.Name == y.Name && x.Size == y.Size && x.Time == y.Time && x.Type == y.Type
				)
				return true;
			return false;
		}

		public int GetHashCode(CredentialFile obj)
		{
			return obj.GetHashCode();
		}
	}
}